import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http';
import { Injectable } from "@angular/core";
import { RequestCache } from '../services/request-cache.service';
import { Observable, of } from 'rxjs';
import { tap, startWith } from 'rxjs/operators';

/**
 * If request is cachable (e.g., package search) and
 * response is in cache return the cached response as observable.
 * If has 'x-refresh' header that is true,
 * then also re-run the package search, using response from next(),
 * returning an observable that emits the cached response first.
 *
 * If not in cache or not cachable,
 * pass request through to next()
 */
@Injectable()
export class CachingInterceptor implements HttpInterceptor{
    constructor(private cache:RequestCache){}

    intercept(req:HttpRequest<any>, next:HttpHandler){
        if(!isCachable(req)){return next.handle(req);}

        const cachedResponse = this.cache.get(req);
        //* cache-then-refresh
        if(req.headers.get('x-refresh')){
            const results$ = sendRequest(req,next,this.cache);
            return cachedResponse? results$.pipe(startWith(cachedResponse)):results$;
        }

        //* cache-or-fetch
        return cachedResponse? of(cachedResponse) : sendRequest(req,next,this.cache);
    }
}

function isCachable(req:HttpRequest<any>){
    //根据 req 中的内容判断是否可缓存。
    return false;
}

/**
 * Get server response observable by sending request to `next()`.
 * Will add the response to the cache on the way out.
 */
function sendRequest(
    req: HttpRequest<any>,
    next: HttpHandler,
    cache: RequestCache): Observable<HttpEvent<any>> {
  
    // No headers allowed in npm search request
    const noHeaderReq = req.clone({ headers: new HttpHeaders() });
  
    return next.handle(noHeaderReq).pipe(
      tap(event => {
        // There may be other events besides the response.
        if (event instanceof HttpResponse) {
          cache.put(req, event); // Update the cache.
        }
      })
    );
  }
  